home *** CD-ROM | disk | FTP | other *** search
/ Network CD 2 / Network CD - Volume 2.iso / programs / internet / tcp / clients / atcp_ttcp10.lha / orig / TTCP.C < prev   
Encoding:
C/C++ Source or Header  |  1993-09-20  |  18.6 KB  |  838 lines

  1. /*
  2.  *    T T C P . C
  3.  *
  4.  * Test TCP connection.  Makes a connection on port 5001
  5.  * and transfers fabricated buffers or data copied from stdin.
  6.  *
  7.  * Usable on 4.2, 4.3, and 4.1a systems by defining one of
  8.  * BSD42 BSD43 (BSD41a)
  9.  * Machines using System V with BSD sockets should define SYSV.
  10.  *
  11.  * Modified for operation under 4.2BSD, 18 Dec 84
  12.  *      T.C. Slattery, USNA
  13.  * Minor improvements, Mike Muuss and Terry Slattery, 16-Oct-85.
  14.  * Modified in 1989 at Silicon Graphics, Inc.
  15.  *    catch SIGPIPE to be able to print stats when receiver has died 
  16.  *    for tcp, don't look for sentinel during reads to allow small transfers
  17.  *    increased default buffer size to 8K, nbuf to 2K to transfer 16MB
  18.  *    moved default port to 5001, beyond IPPORT_USERRESERVED
  19.  *    make sinkmode default because it is more popular, 
  20.  *        -s now means don't sink/source 
  21.  *    count number of read/write system calls to see effects of 
  22.  *        blocking from full socket buffers
  23.  *    for tcp, -D option turns off buffered writes (sets TCP_NODELAY sockopt)
  24.  *    buffer alignment options, -A and -O
  25.  *    print stats in a format that's a bit easier to use with grep & awk
  26.  *    for SYSV, mimic BSD routines to use most of the existing timing code
  27.  * Modified by Steve Miller of the University of Maryland, College Park
  28.  *    -b sets the socket buffer size (SO_SNDBUF/SO_RCVBUF)
  29.  * Modified Sept. 1989 at Silicon Graphics, Inc.
  30.  *    restored -s sense at request of tcs@brl
  31.  * Modified Oct. 1991 at Silicon Graphics, Inc.
  32.  *    use getopt(3) for option processing, add -f and -T options.
  33.  *    SGI IRIX 3.3 and 4.0 releases don't need #define SYSV.
  34.  *
  35.  * Distribution Status -
  36.  *      Public Domain.  Distribution Unlimited.
  37.  */
  38. #ifndef lint
  39. static char RCSid[] = "ttcp.c $Revision: 1.9 $";
  40. #endif
  41.  
  42. #define BSD43
  43. /* #define BSD42 */
  44. /* #define BSD41a */
  45. /* #define SYSV */    /* required on SGI IRIX releases before 3.3 */
  46.  
  47. #include <stdio.h>
  48. #include <signal.h>
  49. #include <ctype.h>
  50. #include <errno.h>
  51. #include <sys/types.h>
  52. #include <sys/socket.h>
  53. #include <netinet/in.h>
  54. #include <netinet/tcp.h>
  55. #include <arpa/inet.h>
  56. #include <netdb.h>
  57. #include <sys/time.h>        /* struct timeval */
  58.  
  59. #if defined(SYSV)
  60. #include <sys/times.h>
  61. #include <sys/param.h>
  62. struct rusage {
  63.     struct timeval ru_utime, ru_stime;
  64. };
  65. #define RUSAGE_SELF 0
  66. #else
  67. #include <sys/resource.h>
  68. #endif
  69.  
  70. struct sockaddr_in sinme;
  71. struct sockaddr_in sinhim;
  72. struct sockaddr_in frominet;
  73.  
  74. int domain, fromlen;
  75. int fd;                /* fd of network socket */
  76.  
  77. int buflen = 8 * 1024;        /* length of buffer */
  78. char *buf;            /* ptr to dynamic buffer */
  79. int nbuf = 2 * 1024;        /* number of buffers to send in sinkmode */
  80.  
  81. int bufoffset = 0;        /* align buffer to this */
  82. int bufalign = 16*1024;        /* modulo this */
  83.  
  84. int udp = 0;            /* 0 = tcp, !0 = udp */
  85. int options = 0;        /* socket options */
  86. int one = 1;                    /* for 4.3 BSD style setsockopt() */
  87. short port = 5001;        /* TCP port number */
  88. char *host;            /* ptr to name of host */
  89. int trans;            /* 0=receive, !0=transmit mode */
  90. int sinkmode = 0;        /* 0=normal I/O, !0=sink/source mode */
  91. int verbose = 0;        /* 0=print basic info, 1=print cpu rate, proc
  92.                  * resource usage. */
  93. int nodelay = 0;        /* set TCP_NODELAY socket option */
  94. int b_flag = 0;            /* use mread() */
  95. int sockbufsize = 0;        /* socket buffer size to use */
  96. char fmt = 'K';            /* output format: k = kilobits, K = kilobytes,
  97.                  *  m = megabits, M = megabytes, 
  98.                  *  g = gigabits, G = gigabytes */
  99. int touchdata = 0;        /* access data after reading */
  100.  
  101. struct hostent *addr;
  102. extern int errno;
  103. extern int optind;
  104. extern char *optarg;
  105.  
  106. char Usage[] = "\
  107. Usage: ttcp -t [-options] host [ < in ]\n\
  108.        ttcp -r [-options > out]\n\
  109. Common options:\n\
  110.     -l ##    length of bufs read from or written to network (default 8192)\n\
  111.     -u    use UDP instead of TCP\n\
  112.     -p ##    port number to send to or listen at (default 5001)\n\
  113.     -s    -t: source a pattern to network\n\
  114.         -r: sink (discard) all data from network\n\
  115.     -A    align the start of buffers to this modulus (default 16384)\n\
  116.     -O    start buffers at this offset from the modulus (default 0)\n\
  117.     -v    verbose: print more statistics\n\
  118.     -d    set SO_DEBUG socket option\n\
  119.     -b ##    set socket buffer size (if supported)\n\
  120.     -f X    format for rate: k,K = kilo{bit,byte}; m,M = mega; g,G = giga\n\
  121. Options specific to -t:\n\
  122.     -n##    number of source bufs written to network (default 2048)\n\
  123.     -D    don't buffer TCP writes (sets TCP_NODELAY socket option)\n\
  124. Options specific to -r:\n\
  125.     -B    for -s, only output full blocks as specified by -l (for TAR)\n\
  126.     -T    \"touch\": access each byte as it's read\n\
  127. ";    
  128.  
  129. char stats[128];
  130. unsigned long nbytes;        /* bytes on net */
  131. unsigned long numCalls;        /* # of I/O system calls */
  132. double cput, realt;        /* user, real time (seconds) */
  133.  
  134. void err();
  135. void mes();
  136. int pattern();
  137. void prep_timer();
  138. double read_timer();
  139. int Nread();
  140. int Nwrite();
  141. void delay();
  142. int mread();
  143. char *outfmt();
  144.  
  145. void
  146. sigpipe()
  147. {
  148. }
  149.  
  150. main(argc,argv)
  151. int argc;
  152. char **argv;
  153. {
  154.     unsigned long addr_tmp;
  155.     int c;
  156.  
  157.     if (argc < 2) goto usage;
  158.  
  159.     while ((c = getopt(argc, argv, "drstuvBDTb:f:l:n:p:A:O:")) != -1) {
  160.         switch (c) {
  161.  
  162.         case 'B':
  163.             b_flag = 1;
  164.             break;
  165.         case 't':
  166.             trans = 1;
  167.             break;
  168.         case 'r':
  169.             trans = 0;
  170.             break;
  171.         case 'd':
  172.             options |= SO_DEBUG;
  173.             break;
  174.         case 'D':
  175. #ifdef TCP_NODELAY
  176.             nodelay = 1;
  177. #else
  178.             fprintf(stderr, 
  179.     "ttcp: -D option ignored: TCP_NODELAY socket option not supported\n");
  180. #endif
  181.             break;
  182.         case 'n':
  183.             nbuf = atoi(optarg);
  184.             break;
  185.         case 'l':
  186.             buflen = atoi(optarg);
  187.             break;
  188.         case 's':
  189.             sinkmode = !sinkmode;
  190.             break;
  191.         case 'p':
  192.             port = atoi(optarg);
  193.             break;
  194.         case 'u':
  195.             udp = 1;
  196.             break;
  197.         case 'v':
  198.             verbose = 1;
  199.             break;
  200.         case 'A':
  201.             bufalign = atoi(optarg);
  202.             break;
  203.         case 'O':
  204.             bufoffset = atoi(optarg);
  205.             break;
  206.         case 'b':
  207. #if defined(SO_SNDBUF) || defined(SO_RCVBUF)
  208.             sockbufsize = atoi(optarg);
  209. #else
  210.             fprintf(stderr, 
  211. "ttcp: -b option ignored: SO_SNDBUF/SO_RCVBUF socket options not supported\n");
  212. #endif
  213.             break;
  214.         case 'f':
  215.             fmt = *optarg;
  216.             break;
  217.         case 'T':
  218.             touchdata = 1;
  219.             break;
  220.  
  221.         default:
  222.             goto usage;
  223.         }
  224.     }
  225.     if(trans)  {
  226.         /* xmitr */
  227.         if (optind == argc)
  228.             goto usage;
  229.         bzero((char *)&sinhim, sizeof(sinhim));
  230.         host = argv[optind];
  231.         if (atoi(host) > 0 )  {
  232.             /* Numeric */
  233.             sinhim.sin_family = AF_INET;
  234. #if defined(cray)
  235.             addr_tmp = inet_addr(host);
  236.             sinhim.sin_addr = addr_tmp;
  237. #else
  238.             sinhim.sin_addr.s_addr = inet_addr(host);
  239. #endif
  240.         } else {
  241.             if ((addr=gethostbyname(host)) == NULL)
  242.                 err("bad hostname");
  243.             sinhim.sin_family = addr->h_addrtype;
  244.             bcopy(addr->h_addr,(char*)&addr_tmp, addr->h_length);
  245. #if defined(cray)
  246.             sinhim.sin_addr = addr_tmp;
  247. #else
  248.             sinhim.sin_addr.s_addr = addr_tmp;
  249. #endif /* cray */
  250.         }
  251.         sinhim.sin_port = htons(port);
  252.         sinme.sin_port = 0;        /* free choice */
  253.     } else {
  254.         /* rcvr */
  255.         sinme.sin_port =  htons(port);
  256.     }
  257.  
  258.  
  259.     if (udp && buflen < 5) {
  260.         buflen = 5;        /* send more than the sentinel size */
  261.     }
  262.  
  263.     if ( (buf = (char *)malloc(buflen+bufalign)) == (char *)NULL)
  264.         err("malloc");
  265.     if (bufalign != 0)
  266.         buf +=(bufalign - ((int)buf % bufalign) + bufoffset) % bufalign;
  267.  
  268.     if (trans) {
  269.         fprintf(stdout,
  270.         "ttcp-t: buflen=%d, nbuf=%d, align=%d/%d, port=%d",
  271.         buflen, nbuf, bufalign, bufoffset, port);
  272.          if (sockbufsize)
  273.          fprintf(stdout, ", sockbufsize=%d", sockbufsize);
  274.          fprintf(stdout, "  %s  -> %s\n", udp?"udp":"tcp", host);
  275.     } else {
  276.         fprintf(stdout,
  277.          "ttcp-r: buflen=%d, nbuf=%d, align=%d/%d, port=%d",
  278.          buflen, nbuf, bufalign, bufoffset, port);
  279.          if (sockbufsize)
  280.          fprintf(stdout, ", sockbufsize=%d", sockbufsize);
  281.          fprintf(stdout, "  %s\n", udp?"udp":"tcp");
  282.     }
  283.  
  284.     if ((fd = socket(AF_INET, udp?SOCK_DGRAM:SOCK_STREAM, 0)) < 0)
  285.         err("socket");
  286.     mes("socket");
  287.  
  288.     if (bind(fd, &sinme, sizeof(sinme)) < 0)
  289.         err("bind");
  290.  
  291. #if defined(SO_SNDBUF) || defined(SO_RCVBUF)
  292.     if (sockbufsize) {
  293.         if (trans) {
  294.         if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sockbufsize,
  295.             sizeof sockbufsize) < 0)
  296.             err("setsockopt: sndbuf");
  297.         mes("sndbuf");
  298.         } else {
  299.         if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &sockbufsize,
  300.             sizeof sockbufsize) < 0)
  301.             err("setsockopt: rcvbuf");
  302.         mes("rcvbuf");
  303.         }
  304.     }
  305. #endif
  306.  
  307.     if (!udp)  {
  308.         signal(SIGPIPE, sigpipe);
  309.         if (trans) {
  310.         /* We are the client if transmitting */
  311.         if (options)  {
  312. #if defined(BSD42)
  313.             if( setsockopt(fd, SOL_SOCKET, options, 0, 0) < 0)
  314. #else /* BSD43 */
  315.             if( setsockopt(fd, SOL_SOCKET, options, &one, sizeof(one)) < 0)
  316. #endif
  317.                 err("setsockopt");
  318.         }
  319. #ifdef TCP_NODELAY
  320.         if (nodelay) {
  321.             struct protoent *p;
  322.             p = getprotobyname("tcp");
  323.             if( p && setsockopt(fd, p->p_proto, TCP_NODELAY, 
  324.                 &one, sizeof(one)) < 0)
  325.                 err("setsockopt: nodelay");
  326.             mes("nodelay");
  327.         }
  328. #endif
  329.         if(connect(fd, &sinhim, sizeof(sinhim) ) < 0)
  330.             err("connect");
  331.         mes("connect");
  332.         } else {
  333.         /* otherwise, we are the server and 
  334.              * should listen for the connections
  335.              */
  336.         listen(fd,0);   /* allow a queue of 0 */
  337.         if(options)  {
  338. #if defined(BSD42)
  339.             if( setsockopt(fd, SOL_SOCKET, options, 0, 0) < 0)
  340. #else /* BSD43 */
  341.             if( setsockopt(fd, SOL_SOCKET, options, &one, sizeof(one)) < 0)
  342. #endif
  343.                 err("setsockopt");
  344.         }
  345.         fromlen = sizeof(frominet);
  346.         domain = AF_INET;
  347.         if((fd=accept(fd, &frominet, &fromlen) ) < 0)
  348.             err("accept");
  349.         { struct sockaddr_in peer;
  350.           int peerlen = sizeof(peer);
  351.           if (getpeername(fd, (struct sockaddr_in *) &peer, 
  352.                 &peerlen) < 0) {
  353.             err("getpeername");
  354.           }
  355.           fprintf(stderr,"ttcp-r: accept from %s\n", 
  356.             inet_ntoa(peer.sin_addr));
  357.         }
  358.         }
  359.     }
  360.     prep_timer();
  361.     errno = 0;
  362.     if (sinkmode) {      
  363.         register int cnt;
  364.         if (trans)  {
  365.             pattern( buf, buflen );
  366.             if(udp)  (void)Nwrite( fd, buf, 4 ); /* rcvr start */
  367.             while (nbuf-- && Nwrite(fd,buf,buflen) == buflen)
  368.                 nbytes += buflen;
  369.             if(udp)  (void)Nwrite( fd, buf, 4 ); /* rcvr end */
  370.         } else {
  371.             if (udp) {
  372.                 while ((cnt=Nread(fd,buf,buflen)) > 0)  {
  373.                     static int going = 0;
  374.                     if( cnt <= 4 )  {
  375.                         if( going )
  376.                             break;    /* "EOF" */
  377.                         going = 1;
  378.                         prep_timer();
  379.                     } else {
  380.                         nbytes += cnt;
  381.                     }
  382.                 }
  383.             } else {
  384.                 while ((cnt=Nread(fd,buf,buflen)) > 0)  {
  385.                     nbytes += cnt;
  386.                 }
  387.             }
  388.         }
  389.     } else {
  390.         register int cnt;
  391.         if (trans)  {
  392.             while((cnt=read(0,buf,buflen)) > 0 &&
  393.                 Nwrite(fd,buf,cnt) == cnt)
  394.                 nbytes += cnt;
  395.         }  else  {
  396.             while((cnt=Nread(fd,buf,buflen)) > 0 &&
  397.                 write(1,buf,cnt) == cnt)
  398.                 nbytes += cnt;
  399.         }
  400.     }
  401.     if(errno) err("IO");
  402.     (void)read_timer(stats,sizeof(stats));
  403.     if(udp&&trans)  {
  404.         (void)Nwrite( fd, buf, 4 ); /* rcvr end */
  405.         (void)Nwrite( fd, buf, 4 ); /* rcvr end */
  406.         (void)Nwrite( fd, buf, 4 ); /* rcvr end */
  407.         (void)Nwrite( fd, buf, 4 ); /* rcvr end */
  408.     }
  409.     if( cput <= 0.0 )  cput = 0.001;
  410.     if( realt <= 0.0 )  realt = 0.001;
  411.     fprintf(stdout,
  412.         "ttcp%s: %ld bytes in %.2f real seconds = %s/sec +++\n",
  413.         trans?"-t":"-r",
  414.         nbytes, realt, outfmt(((double)nbytes)/realt));
  415.     if (verbose) {
  416.         fprintf(stdout,
  417.         "ttcp%s: %ld bytes in %.2f CPU seconds = %s/cpu sec\n",
  418.         trans?"-t":"-r",
  419.         nbytes, cput, outfmt(((double)nbytes)/cput));
  420.     }
  421.     fprintf(stdout,
  422.         "ttcp%s: %d I/O calls, msec/call = %.2f, calls/sec = %.2f\n",
  423.         trans?"-t":"-r",
  424.         numCalls,
  425.         1024.0 * realt/((double)numCalls),
  426.         ((double)numCalls)/realt);
  427.     fprintf(stdout,"ttcp%s: %s\n", trans?"-t":"-r", stats);
  428.     if (verbose) {
  429.         fprintf(stdout,
  430.         "ttcp%s: buffer address %#x\n",
  431.         trans?"-t":"-r",
  432.         buf);
  433.     }
  434.     exit(0);
  435.  
  436. usage:
  437.     fprintf(stderr,Usage);
  438.     exit(1);
  439. }
  440.  
  441. void
  442. err(s)
  443. char *s;
  444. {
  445.     fprintf(stderr,"ttcp%s: ", trans?"-t":"-r");
  446.     perror(s);
  447.     fprintf(stderr,"errno=%d\n",errno);
  448.     exit(1);
  449. }
  450.  
  451. void
  452. mes(s)
  453. char *s;
  454. {
  455.     fprintf(stderr,"ttcp%s: %s\n", trans?"-t":"-r", s);
  456. }
  457.  
  458. pattern( cp, cnt )
  459. register char *cp;
  460. register int cnt;
  461. {
  462.     register char c;
  463.     c = 0;
  464.     while( cnt-- > 0 )  {
  465.         while( !isprint((c&0x7F)) )  c++;
  466.         *cp++ = (c++&0x7F);
  467.     }
  468. }
  469.  
  470. char *
  471. outfmt(b)
  472. double b;
  473. {
  474.     static char obuf[50];
  475.     switch (fmt) {
  476.     case 'G':
  477.         sprintf(obuf, "%.2f GB", b / 1024.0 / 1024.0 / 1024.0);
  478.         break;
  479.     default:
  480.     case 'K':
  481.         sprintf(obuf, "%.2f KB", b / 1024.0);
  482.         break;
  483.     case 'M':
  484.         sprintf(obuf, "%.2f MB", b / 1024.0 / 1024.0);
  485.         break;
  486.     case 'g':
  487.         sprintf(obuf, "%.2f Gbit", b * 8.0 / 1024.0 / 1024.0 / 1024.0);
  488.         break;
  489.     case 'k':
  490.         sprintf(obuf, "%.2f Kbit", b * 8.0 / 1024.0);
  491.         break;
  492.     case 'm':
  493.         sprintf(obuf, "%.2f Mbit", b * 8.0 / 1024.0 / 1024.0);
  494.         break;
  495.     }
  496.     return obuf;
  497. }
  498.  
  499. static struct    timeval time0;    /* Time at which timing started */
  500. static struct    rusage ru0;    /* Resource utilization at the start */
  501.  
  502. static void prusage();
  503. static void tvadd();
  504. static void tvsub();
  505. static void psecs();
  506.  
  507. #if defined(SYSV)
  508. /*ARGSUSED*/
  509. static
  510. getrusage(ignored, ru)
  511.     int ignored;
  512.     register struct rusage *ru;
  513. {
  514.     struct tms buf;
  515.  
  516.     times(&buf);
  517.  
  518.     /* Assumption: HZ <= 2147 (LONG_MAX/1000000) */
  519.     ru->ru_stime.tv_sec  = buf.tms_stime / HZ;
  520.     ru->ru_stime.tv_usec = ((buf.tms_stime % HZ) * 1000000) / HZ;
  521.     ru->ru_utime.tv_sec  = buf.tms_utime / HZ;
  522.     ru->ru_utime.tv_usec = ((buf.tms_utime % HZ) * 1000000) / HZ;
  523. }
  524.  
  525. /*ARGSUSED*/
  526. static 
  527. gettimeofday(tp, zp)
  528.     struct timeval *tp;
  529.     struct timezone *zp;
  530. {
  531.     tp->tv_sec = time(0);
  532.     tp->tv_usec = 0;
  533. }
  534. #endif /* SYSV */
  535.  
  536. /*
  537.  *            P R E P _ T I M E R
  538.  */
  539. void
  540. prep_timer()
  541. {
  542.     gettimeofday(&time0, (struct timezone *)0);
  543.     getrusage(RUSAGE_SELF, &ru0);
  544. }
  545.  
  546. /*
  547.  *            R E A D _ T I M E R
  548.  * 
  549.  */
  550. double
  551. read_timer(str,len)
  552. char *str;
  553. {
  554.     struct timeval timedol;
  555.     struct rusage ru1;
  556.     struct timeval td;
  557.     struct timeval tend, tstart;
  558.     char line[132];
  559.  
  560.     getrusage(RUSAGE_SELF, &ru1);
  561.     gettimeofday(&timedol, (struct timezone *)0);
  562.     prusage(&ru0, &ru1, &timedol, &time0, line);
  563.     (void)strncpy( str, line, len );
  564.  
  565.     /* Get real time */
  566.     tvsub( &td, &timedol, &time0 );
  567.     realt = td.tv_sec + ((double)td.tv_usec) / 1000000;
  568.  
  569.     /* Get CPU time (user+sys) */
  570.     tvadd( &tend, &ru1.ru_utime, &ru1.ru_stime );
  571.     tvadd( &tstart, &ru0.ru_utime, &ru0.ru_stime );
  572.     tvsub( &td, &tend, &tstart );
  573.     cput = td.tv_sec + ((double)td.tv_usec) / 1000000;
  574.     if( cput < 0.00001 )  cput = 0.00001;
  575.     return( cput );
  576. }
  577.  
  578. static void
  579. prusage(r0, r1, e, b, outp)
  580.     register struct rusage *r0, *r1;
  581.     struct timeval *e, *b;
  582.     char *outp;
  583. {
  584.     struct timeval tdiff;
  585.     register time_t t;
  586.     register char *cp;
  587.     register int i;
  588.     int ms;
  589.  
  590.     t = (r1->ru_utime.tv_sec-r0->ru_utime.tv_sec)*100+
  591.         (r1->ru_utime.tv_usec-r0->ru_utime.tv_usec)/10000+
  592.         (r1->ru_stime.tv_sec-r0->ru_stime.tv_sec)*100+
  593.         (r1->ru_stime.tv_usec-r0->ru_stime.tv_usec)/10000;
  594.     ms =  (e->tv_sec-b->tv_sec)*100 + (e->tv_usec-b->tv_usec)/10000;
  595.  
  596. #define END(x)    {while(*x) x++;}
  597. #if defined(SYSV)
  598.     cp = "%Uuser %Ssys %Ereal %P";
  599. #else
  600. #if defined(sgi)        /* IRIX 3.3 will show 0 for %M,%F,%R,%C */
  601.     cp = "%Uuser %Ssys %Ereal %P %Mmaxrss %F+%Rpf %Ccsw";
  602. #else
  603.     cp = "%Uuser %Ssys %Ereal %P %Xi+%Dd %Mmaxrss %F+%Rpf %Ccsw";
  604. #endif
  605. #endif
  606.     for (; *cp; cp++)  {
  607.         if (*cp != '%')
  608.             *outp++ = *cp;
  609.         else if (cp[1]) switch(*++cp) {
  610.  
  611.         case 'U':
  612.             tvsub(&tdiff, &r1->ru_utime, &r0->ru_utime);
  613.             sprintf(outp,"%d.%01d", tdiff.tv_sec, tdiff.tv_usec/100000);
  614.             END(outp);
  615.             break;
  616.  
  617.         case 'S':
  618.             tvsub(&tdiff, &r1->ru_stime, &r0->ru_stime);
  619.             sprintf(outp,"%d.%01d", tdiff.tv_sec, tdiff.tv_usec/100000);
  620.             END(outp);
  621.             break;
  622.  
  623.         case 'E':
  624.             psecs(ms / 100, outp);
  625.             END(outp);
  626.             break;
  627.  
  628.         case 'P':
  629.             sprintf(outp,"%d%%", (int) (t*100 / ((ms ? ms : 1))));
  630.             END(outp);
  631.             break;
  632.  
  633. #if !defined(SYSV)
  634.         case 'W':
  635.             i = r1->ru_nswap - r0->ru_nswap;
  636.             sprintf(outp,"%d", i);
  637.             END(outp);
  638.             break;
  639.  
  640.         case 'X':
  641.             sprintf(outp,"%d", t == 0 ? 0 : (r1->ru_ixrss-r0->ru_ixrss)/t);
  642.             END(outp);
  643.             break;
  644.  
  645.         case 'D':
  646.             sprintf(outp,"%d", t == 0 ? 0 :
  647.                 (r1->ru_idrss+r1->ru_isrss-(r0->ru_idrss+r0->ru_isrss))/t);
  648.             END(outp);
  649.             break;
  650.  
  651.         case 'K':
  652.             sprintf(outp,"%d", t == 0 ? 0 :
  653.                 ((r1->ru_ixrss+r1->ru_isrss+r1->ru_idrss) -
  654.                 (r0->ru_ixrss+r0->ru_idrss+r0->ru_isrss))/t);
  655.             END(outp);
  656.             break;
  657.  
  658.         case 'M':
  659.             sprintf(outp,"%d", r1->ru_maxrss/2);
  660.             END(outp);
  661.             break;
  662.  
  663.         case 'F':
  664.             sprintf(outp,"%d", r1->ru_majflt-r0->ru_majflt);
  665.             END(outp);
  666.             break;
  667.  
  668.         case 'R':
  669.             sprintf(outp,"%d", r1->ru_minflt-r0->ru_minflt);
  670.             END(outp);
  671.             break;
  672.  
  673.         case 'I':
  674.             sprintf(outp,"%d", r1->ru_inblock-r0->ru_inblock);
  675.             END(outp);
  676.             break;
  677.  
  678.         case 'O':
  679.             sprintf(outp,"%d", r1->ru_oublock-r0->ru_oublock);
  680.             END(outp);
  681.             break;
  682.         case 'C':
  683.             sprintf(outp,"%d+%d", r1->ru_nvcsw-r0->ru_nvcsw,
  684.                 r1->ru_nivcsw-r0->ru_nivcsw );
  685.             END(outp);
  686.             break;
  687. #endif /* !SYSV */
  688.         }
  689.     }
  690.     *outp = '\0';
  691. }
  692.  
  693. static void
  694. tvadd(tsum, t0, t1)
  695.     struct timeval *tsum, *t0, *t1;
  696. {
  697.  
  698.     tsum->tv_sec = t0->tv_sec + t1->tv_sec;
  699.     tsum->tv_usec = t0->tv_usec + t1->tv_usec;
  700.     if (tsum->tv_usec > 1000000)
  701.         tsum->tv_sec++, tsum->tv_usec -= 1000000;
  702. }
  703.  
  704. static void
  705. tvsub(tdiff, t1, t0)
  706.     struct timeval *tdiff, *t1, *t0;
  707. {
  708.  
  709.     tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
  710.     tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
  711.     if (tdiff->tv_usec < 0)
  712.         tdiff->tv_sec--, tdiff->tv_usec += 1000000;
  713. }
  714.  
  715. static void
  716. psecs(l,cp)
  717. long l;
  718. register char *cp;
  719. {
  720.     register int i;
  721.  
  722.     i = l / 3600;
  723.     if (i) {
  724.         sprintf(cp,"%d:", i);
  725.         END(cp);
  726.         i = l % 3600;
  727.         sprintf(cp,"%d%d", (i/60) / 10, (i/60) % 10);
  728.         END(cp);
  729.     } else {
  730.         i = l;
  731.         sprintf(cp,"%d", i / 60);
  732.         END(cp);
  733.     }
  734.     i %= 60;
  735.     *cp++ = ':';
  736.     sprintf(cp,"%d%d", i / 10, i % 10);
  737. }
  738.  
  739. /*
  740.  *            N R E A D
  741.  */
  742. Nread( fd, buf, count )
  743. int fd;
  744. void *buf;
  745. int count;
  746. {
  747.     struct sockaddr_in from;
  748.     int len = sizeof(from);
  749.     register int cnt;
  750.     if( udp )  {
  751.         cnt = recvfrom( fd, buf, count, 0, &from, &len );
  752.         numCalls++;
  753.     } else {
  754.         if( b_flag )
  755.             cnt = mread( fd, buf, count );    /* fill buf */
  756.         else {
  757.             cnt = read( fd, buf, count );
  758.             numCalls++;
  759.         }
  760.         if (touchdata && cnt > 0) {
  761.             register int c = cnt, sum;
  762.             register char *b = buf;
  763.             while (c--)
  764.                 sum += *b++;
  765.         }
  766.     }
  767.     return(cnt);
  768. }
  769.  
  770. /*
  771.  *            N W R I T E
  772.  */
  773. Nwrite( fd, buf, count )
  774. int fd;
  775. void *buf;
  776. int count;
  777. {
  778.     register int cnt;
  779.     if( udp )  {
  780. again:
  781.         cnt = sendto( fd, buf, count, 0, &sinhim, sizeof(sinhim) );
  782.         numCalls++;
  783.         if( cnt<0 && errno == ENOBUFS )  {
  784.             delay(18000);
  785.             errno = 0;
  786.             goto again;
  787.         }
  788.     } else {
  789.         cnt = write( fd, buf, count );
  790.         numCalls++;
  791.     }
  792.     return(cnt);
  793. }
  794.  
  795. void
  796. delay(us)
  797. {
  798.     struct timeval tv;
  799.  
  800.     tv.tv_sec = 0;
  801.     tv.tv_usec = us;
  802.     (void)select( 1, (char *)0, (char *)0, (char *)0, &tv );
  803. }
  804.  
  805. /*
  806.  *            M R E A D
  807.  *
  808.  * This function performs the function of a read(II) but will
  809.  * call read(II) multiple times in order to get the requested
  810.  * number of characters.  This can be necessary because
  811.  * network connections don't deliver data with the same
  812.  * grouping as it is written with.  Written by Robert S. Miles, BRL.
  813.  */
  814. int
  815. mread(fd, bufp, n)
  816. int fd;
  817. register char    *bufp;
  818. unsigned    n;
  819. {
  820.     register unsigned    count = 0;
  821.     register int        nread;
  822.  
  823.     do {
  824.         nread = read(fd, bufp, n-count);
  825.         numCalls++;
  826.         if(nread < 0)  {
  827.             perror("ttcp_mread");
  828.             return(-1);
  829.         }
  830.         if(nread == 0)
  831.             return((int)count);
  832.         count += (unsigned)nread;
  833.         bufp += nread;
  834.      } while(count < n);
  835.  
  836.     return((int)count);
  837. }
  838.